import java.awt.Point;
import java.util.Random;
import java.awt.geom.Point2D;

public class ServerPlayerEntity extends ServerEntity {

	final int movementcooldown = 250;

	final int abilitycooldown = 300;

	final Random gen = new Random();

	long currentTime = 0;

	Point toActOn = null;

	int damageAmount = 0;

	public ServerPlayerEntity(PlayerEntityData data, Map map,
			ServerMessageSender ms) {
		super(data, map, ms);
	}

	public int takeDamage(int accessory, int weapon) {
		if (gen.nextDouble() < .5 * ((double) (accessory) / data.hat)) {
			// if hit
			int damageAmount = 15 + gen.nextInt(weapon)
					- (int) (.25 * data.hat);
			if (damageAmount <= 0)
				return 0;
			if (data.hp - damageAmount <= 0) {
				data.hp = EntityData.HP_DEFAULT;
				while (!map.move(this, new Point(gen.nextInt(100), gen
						.nextInt(100)))) {
				}
				try {
					ms.playerHealthUpdate(((PlayerEntityData) data).ip,
							data.id, data.hp);
					ms.playerPositionUpdate(data.id, data.location.x,
							data.location.y);
				} catch (Exception e) {
					e.printStackTrace();
				}
				return data.xp;
			} else {
				data.hp = data.hp - damageAmount;
				ms.playerHealthUpdate(((PlayerEntityData) data).ip, data.id,
						data.hp);
				return 0;
			}
		}
		return 0;
	}

	public void processMessage(Message m) {
		currentTime = System.currentTimeMillis();
		if (m instanceof ClientPlayerMoveMessage) {
			if (currentTime - lastActed > movementcooldown) {
				toActOn = new Point(((ClientPlayerMoveMessage) m).getX(),
						((ClientPlayerMoveMessage) m).getY());
				if (map.isEmpty(toActOn) && isInRange(toActOn)
						&& map.move(this, toActOn))
					ms.playerPositionUpdate(data.id, data.location.x,
							data.location.y);
				lastActed = System.currentTimeMillis();
			}
		}
		if (m instanceof ClientPlayerUseAbilityMessage) {
			if (currentTime - lastActed >= abilitycooldown) {
				int type = ((ClientPlayerUseAbilityMessage) m).type;
				toActOn = new Point(((ClientPlayerUseAbilityMessage) m).x,
						((ClientPlayerUseAbilityMessage) m).y);
				if (type == ClientPlayerUseAbilityMessage.ATTACK) {
					attack(toActOn);
				}
				if (type == ClientPlayerUseAbilityMessage.SPECIAL) {
					if (data.mana >= PlayerEntityData.MANASPECIAL) {
						try {
							data.mana = data.mana
									- PlayerEntityData.MANASPECIAL;
							// mana update
							ms.playerManaUpdate(((PlayerEntityData) data).ip,
									data.id, data.mana);
							attack(new Point(data.location.x,
									data.location.y + 1));
							attack(new Point(data.location.x + 1,
									data.location.y));
							attack(new Point(data.location.x,
									data.location.y - 1));
							attack(new Point(data.location.x - 1,
									data.location.y));
						} catch (Exception e) {
							System.out.println(e);
						}
					}
				}
				if (type == ClientPlayerUseAbilityMessage.HEALTH) {
					if (((PlayerEntityData) data).healthpots >= 1) {
						data.hp = data.hp + PlayerEntityData.HEALTHPOTSRECOVERY;
						if (data.hp > data.hpMax)
							data.hp = data.hpMax;
						ms.playerHealthUpdate(((PlayerEntityData) data).ip,
								data.id, data.hp);
						((PlayerEntityData) data).healthpots--;
						// update # of healthpots
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
					}
				}
				if (type == ClientPlayerUseAbilityMessage.MANA) {
					if (((PlayerEntityData) data).manapots >= 1) {
						try {
							data.mana = data.mana
									+ PlayerEntityData.MANAPOTSRECOVERY;
							if (data.mana > data.manaMax)
								data.mana = data.manaMax;
							// update mana
							ms.playerManaUpdate(((PlayerEntityData) data).ip,
									data.id, data.mana);
							((PlayerEntityData) data).manapots--;
							// update # of manapots
							ms.playerInventoryUpdate(
									((PlayerEntityData) data).ip, data.id,
									data.hat, data.weapon,
									((PlayerEntityData) data).accessory,
									((PlayerEntityData) data).manapots,
									((PlayerEntityData) data).healthpots);
						} catch (Exception e) {
							System.out.println(e);
						}
					}
				}
				lastActed = System.currentTimeMillis();
			}
		}
	}

	public boolean isInRange(Point loc) {
		return ((Point2D) loc).distance((Point2D) this.data.location) <= 1;
	}

	public void attack(Point toAttack) {
		if (!map.isEmpty(toAttack) && isInRange(toAttack)) {
			int xpUp = ((ServerEntity) map.get(toAttack)).takeDamage(
					((PlayerEntityData) data).accessory, data.weapon);
			if (xpUp != 0) {
				try {
					data.xp += xpUp;
					// xp update
					switch (gen.nextInt(7)) {
					case 0:// hp update
						data.hp = data.hpMax;
						ms.playerHealthUpdate(((PlayerEntityData) data).ip,
								data.id, data.hp);
						break;
					case 1:// mana update
						data.mana = data.manaMax;
						ms.playerManaUpdate(((PlayerEntityData) data).ip,
								data.id, data.mana);
						break;
					case 2:// mana pot
						((PlayerEntityData) data).manapots++;
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
						break;
					case 3:// health pot
						((PlayerEntityData) data).healthpots++;
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
						break;
					case 4:// hat update
						data.hat = data.hat + 2;
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
						break;
					case 5:// weapon update
						data.weapon = data.weapon + 2;
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
						break;
					case 6:// accessory update
						((PlayerEntityData) data).accessory = ((PlayerEntityData) data).accessory + 2;
						ms.playerInventoryUpdate(((PlayerEntityData) data).ip,
								data.id, data.hat, data.weapon,
								((PlayerEntityData) data).accessory,
								((PlayerEntityData) data).manapots,
								((PlayerEntityData) data).healthpots);
						break;
					}
				} catch (Exception e) {
					System.out.println(e);
				}
			}
		}
	}
}